#ifndef CHATSERVICE_H
#define CHATSERVICE_H

#include <muduo/net/TcpConnection.h>
#include <functional>
#include <mutex>
#include <iostream>
#include <unordered_map>

#include "redis.hpp"
#include "usermodel.hpp"
#include "offlinemsgmodel.hpp"
#include "friendmodel.hpp"
#include "groupmodel.hpp"
#include "connectionPool.hpp"

using namespace std;
using namespace muduo;
using namespace muduo::net;

#include "json.hpp"
using json = nlohmann::json;
using namespace std::placeholders;
using MsgHandler = function<void(const TcpConnectionPtr &, json &, Timestamp)>;
/**
 * @brief 业务类
 *
 */
class ChatService
{
public:
    static ChatService *getInstance(); // 获取实例
    // 业务
    void login(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void reg(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void oneChat(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void addFriend(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void createGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void addGroup(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void groupChat(const TcpConnectionPtr &conn, json &js, Timestamp time);
    void loginout(const TcpConnectionPtr &conn, json &js, Timestamp time);
    // 客户端异常退出
    void clientCloseException(const TcpConnectionPtr &conn);
    // 重置用户状态
    void reset();
    // 获取消息对应的处理函数
    MsgHandler getHandler(int msgid);
    // 从redis消息队列获取订阅信息
    void handlerRedisSubMsg(int id, string msg);

private:
    ChatService();                                     // 单例模式
    unordered_map<int, MsgHandler> _msgHandlerMap;     // 储存消息类和处理函数的映射
    UserModel _userModel;                              // 操作用户
    OfflineMsgModel _offlineMsgModel;                  // 操作离线信息
    FriendModel _friendModel;                          // 操作好友
    GroupModel _groupModel;                            // 操作群组
    unordered_map<int, TcpConnectionPtr> _userConnMap; // 储存用户链接的信息
    mutex _connMutex;                                  // 多线程互斥
    Redis _redis;                                      // 操作redis
};
#endif